<?php

namespace app\models\tableModel;

use app\models\cacheModel\AdminRoleModel as AdminRoleCacheModel;
use app\models\CommonModel;
use app\models\table\AdminRole;
use yii\db\Exception;
use yii\helpers\ArrayHelper;

/**
 * 角色管理[Model]
 * User: Administrator
 * Date: 1995/12/22
 * Time: 17:59
 */
class AdminRoleModel extends AdminRole
{

    /**
     * 状态 列表
     * @var array
     */
    private static $statusList = [
        'disabled' => -1,
        'open' => 1
    ];
    /**
     * 状态文本 列表
     * @var array
     */
    private static $statusListText = [
        -1 => '已禁用',
        1 => '已开启'
    ];
    /**
     * 排序最大值
     * @var int
     */
    protected static $sortMax = 9999999;
    /**
     * 排序最小值
     * @var int
     */
    protected static $sortMin = -999999;
    /**
     * 超管编号列表
     * @var array
     */
    protected static $superRoleId = [
        '1'
    ];

    /**
     * 条件暂存
     * @var array
     */
    public $where = [];

    /**
     * 静态错误暂存
     * @var
     */
    public static $error_;

    /**
     * 规则验证
     * @return array
     */
    public function rules()
    {

        $parent = parent::rules();        // 状态
        $statusList = array_values(self::getStatList());

        return ArrayHelper::merge($parent, [
            ['status', 'in', 'range' => $statusList, 'message' => '状态不合法'],
        ]);
    }

    /**
     * 重写label的 文字
     */
    public function attributeLabels()
    {
        return [
            'id' => '编号',
            'name' => '名称',
            'content' => '内容',
            'update_time' => '更新时间',
            'status' => '状态',
        ];
    }

    /**
     * 场景
     * @return array
     */
    public function scenarios()
    {

        $scenarios = parent::scenarios();
        return ArrayHelper::merge($scenarios, [
            [
                // 自定义场景 (无用请删除)
                'scUpdate' => [
                    'someAttributes'
                ]
            ]
        ]);
    }

    /**
     * 加载整体[Model]
     * @param null $id 编号
     * @param string $scenario 场景
     * @return AdminRoleModel|\yii\db\ActiveQuery|null
     */
    public static function loadModel($id = null, $scenario = 'default')
    {

        // 实力化类
        $model = new self();

        // [id]是空的 仅仅返回[model]
        if ($id == null) return $model;

        // [id]是[true]返回
        if ($id === true) {
            $model = $model::find();
        } else if (!empty($id)) { // 有[id]去查询
            $model = $model::findOne($id);
        }

        // 条目不存在或者需要[find]都返回 - 无法加载场景
        if (!$model || $id === true) {
            return $model;
        }

        // 场景
        $sceList = array_keys($model->scenarios());
        if (!empty($scenario) && in_array($scenario, $sceList)) $model->setScenario($scenario);

        return $model;
    }

    /**
     * 获取全部列表
     * @param $page
     * @param $limit
     * @param null $filed
     * @return array|\yii\db\ActiveRecord[]
     */
    public function getList($page, $limit, $filed = null)
    {

        // 条件
        $where = $this->where;

        // 当前页面计算
        $page = (($page - 1) < 0 ? 0 : ($page - 1));

        // 查找的 字段空的 就默认给列表
        if (!$filed) $filed = '*';


        // 基础[where]加载完毕
        $base = $this::find()->select($filed)->where($where);

        // 数据的获取 分页等
        $list = $base->offset($page * $limit)
            ->limit($limit)
            ->asArray()->all();

        // 格式化数据
        foreach ($list as $k => &$v) {

            // 更新时间
            if (!empty($v['update_time'])) {
                $v['update_time_text'] = date('Y-m-d H:i:s', $v['update_time']);
                $v['update_time_text_s'] = date('Y-m-d', $v['update_time']);
            }

            // 状态文本
            if (isset($v['status'])) {
                $v['status_text'] = self::getStatusText($v['status']);
            }

            // 内容转化下
            if (!empty($v['content'])) {
                $v['content'] = htmlspecialchars_decode($v['content']);
                $v['content'] = CommonModel::addHtmlImgHost($v['content']);
            }

            // 权限 转[json]
            if (isset($v['auth']) && is_array(json_decode($v['auth'], true))) {
                $v['auth'] = json_decode($v['auth'], true);
            }

            // 权限 转[json]
            if (isset($v['menu']) && is_array(json_decode($v['menu'], true))) {
                $v['menu'] = json_decode($v['menu'], true);
            }
        }

        return $list;
    }

    /**
     * 加载条件
     * @param $where
     * @return $this
     */
    public function loadWhere($where)
    {

        // 条件不存在
        if (empty($where)) {

            return $this;
        }

        // 如果[where][0]是'and' 直接赋值
        $canRetList = ['and', 'or', 'AND', 'OR'];
        if (!empty($where[0]) && in_array($where[0], $canRetList)) {

            $this->where = $where;
            return $this;
        }

        // 不是数组 字符直接 判断
        if (!is_array($where)) {

            // 条件是 有效
            if (!empty($where) && $this->hasAttribute($where))

                $this->where = $where;

            // 条件 无有效
            return $this;
        }

        // 循环  条件是否有效
        $stagingWhere = ['and'];
        foreach ($where as $k => $v) {

            // 首先值是有的，不能是空
            if ($v && is_array($v) && count($v) > 0 && $this->hasAttribute($k)) {

                $stagingWhere[] = ['IN', $k, array_values($v)];
                continue;
            }

            // 首先值是有的，不能是空
            if ($v && $k == 'name' && $this->hasAttribute($k)) {

                $stagingWhere[] = ['LIKE', $k, $v];
                continue;
            }
            // 首先值是有的，不能是空
            if ($v && $this->hasAttribute($k))

                $stagingWhere[] = ['=', $k, $v];
        }

        // 条件最终赋值
        $this->where = $stagingWhere;

        return $this;
    }

    /**
     * 获取记录总数量
     * @return int|string
     */
    public function getCount()
    {

        // 条件
        $where = $this->where;

        // 基础 where加载完毕
        $count = $this::find()->where($where)->count();

        return $count;
    }

    /**
     * 添加|保存
     * @param bool $syncCache
     * @return bool
     */
    public function saveData($syncCache = false)
    {

        $dbTran = \Yii::$app->db->beginTransaction();
        try {

            // ************ 1、操作数据库 ************
            $nowTime = time();
            // 添加的话要赋值一些初始数据
            if (empty($this->id)) {

                // 可以是走[mongoId]
                $this->id = CommonModel::newMongoId();
            }

            // 添加时间
            $this->update_time = $nowTime;
            // 内容加密下
            $this->content = htmlspecialchars($this->content);
            // 内容取出图片域名
            $this->content = CommonModel::removeHtmlImgHost($this->content);
            // 保存
            if ($this->hasErrors() || !$this->validate() || !$this->save()) {

                $dbTran->rollBack();
                return false;
            }

            // 如果不更新缓存可以返回
            if (!$syncCache) {
                $dbTran->commit();
                return true;
            }


            // ************ 2、需要操作缓存操作缓存 ************
            // 下面就需要同步全部数据了
            $cacheModel = AdminRoleCacheModel::loadModel($this->id);
            // 数据不存在，再次初始化
            if (empty($cacheModel)) $cacheModel = AdminRoleCacheModel::loadModel();
            // 赋值
            $cacheModel->setAttributes($this->getAttributes());
            // 保存
            if (!$cacheModel->saveData()) {

                $dbTran->rollBack();
                $error = CommonModel::getModelError($cacheModel->errors);
                $this->addError($error['column'], '缓存错误：' . $error['msg']);
                return false;
            }

            $dbTran->commit();
            return true;
        } catch (Exception $error) {

            // 记录下错误日志
            \Yii::error([

                "````````````````````````````````````````````````````````",
                "``                    数据库OR缓存错误                   ``",
                "`` 错误详情: 修改[保存]失败，{$error->getMessage()}       ``",
                "`` 错误信息和参数详情:                                    ``",
                "````````````````````````````````````````````````````````",
                $error->getTraceAsString()
            ], 'normal');
            $this->addError('500', '出现致命错误');
            $dbTran->rollBack();
            return false;
        }
    }

    /**
     * 更新下角色的菜单
     *  `   根据现在角色数据库[auth]值比对出菜单列表保存到[menu]中    `
     *  `   根据数据库更新下缓存  `
     * @return bool
     */
    public function updateMenu()
    {

        // 权限空默认赋值
        if (empty($this->auth)) $this->auth = [];

        // 权限列表
        $authUrlList = array_column($this->auth, 'url');
        // 非空权限获取下合法菜单列表
        $menuList = [];

        // 角色是超管
        if (!empty($authUrlList) && self::isSuper($this->id)) {
            $menuList = AdminMenuModel::loadModel()->filterMenuByAuth($authUrlList, true);
        } else if (!empty($authUrlList)) { // 角色非超管
            $menuList = AdminMenuModel::loadModel()->filterMenuByAuth($authUrlList);
        }

        // 赋值
        $this->setAttributes([
            'menu' => $menuList
        ]);

        // 检测是否保存成功
        if (!$this->saveData()) {
            return false;
        }

        return true;
    }

    /**
     * 更新某些字段
     * @param $condition
     * @param array $fieldVal
     * @param bool $syncCache
     * @return bool
     */
    public static function updateField($condition, $fieldVal = [], $syncCache = true)
    {

        $model = new self();
        foreach ($fieldVal as $k => $v) {

            if (!$model->hasAttribute($k)) {

                unset($fieldVal[$k]);
                continue;
            }
        }

        $db = \Yii::$app->db->createCommand();

        try {

            $result = $db->update(self::tableName(), $fieldVal, $condition)->execute();

            // 如果需要同步缓存 也更新
            if ($syncCache) {
                AdminRoleCacheModel::updateField($condition, $fieldVal);
            }

            // 否则成功
            return true;
        } catch (\Exception $error) {

            // 记录下错误日志
            \Yii::error([

                "````````````````````````````````````````````````````````",
                "``                      数据库错误                      ``",
                "`` 错误详情: 修改[指定字段]失败，{$error->getMessage()}      ``",
                "`` SQL语句: {$db->getRawSql()}                         ``",
                "`` 错误信息和参数详情:                                    ``",
                "````````````````````````````````````````````````````````",
                $error->getTraceAsString()
            ], 'normal');

            self::$error_ = empty($error->errorInfo) ?
                $error->getMessage() :
                implode(' | ', $error->errorInfo);

            return false;
        }
    }

    /**
     * 检测用户编号是否是超管
     * @param null $roleId
     * @return bool
     */
    public static function isSuper($roleId = null)
    {

        if (!in_array($roleId, self::$superRoleId)) {
            return false;
        }

        return true;
    }

    /**
     * 返回排序最大值
     * @return int
     */
    public static function getSortMax()
    {
        return self::$sortMax;
    }

    /**
     * 返回排序最小值
     * @return int
     */
    public static function getSortMin()
    {
        return self::$sortMin;
    }

    /**
     * 获取[正常]状态 值
     * @return mixed|string
     */
    public static function getStatOpen()
    {

        // 最终正常返回
        return self::$statusList['open'];
    }

    /**
     * 获取[禁用]状态 值
     * @return mixed|string
     */
    public static function getStatDisabled()
    {

        // 最终正常返回
        return self::$statusList['disabled'];
    }

    /**
     * 获取[状态]列表 值
     * @return mixed|string
     */
    public static function getStatList()
    {

        // 最终正常返回
        return self::$statusList;
    }

    /**
     * 获取[状态]文本
     * @param $value
     * @return mixed|string
     */
    public static function getStatusText($value)
    {

        // 列表
        $list = self::$statusListText;
        // 不合法 - 不存在
        if (empty($list[$value]))

            return '--';

        // 最终正常返回
        return $list[$value];
    }
}
